package com.dux.commons.network.packet;

import java.nio.ByteBuffer;

import org.apache.log4j.Logger;

import com.dux.commons.network.MMOConnection;

/**
 * 接收到数据包超类
 * @author 杜祥
 * @date 2013-6-1
 */
public abstract class ReceivablePacket<T extends MMOConnection> extends AbstractPacket implements Runnable
{
	/**
	 * 日志输出
	 */
	private static Logger log = Logger.getLogger(ReceivablePacket.class);
	
	/**
	 * 此包的数据字节缓冲流
	 */
	private ByteBuffer buffer;
	
	/**
	 * 数据包的所有者
	 */
	private T connection;
	
	
	/**
	 * 构建一个数据包，并设置操作码和字节缓冲流。
	 * @param opcode
	 * 						操作码
	 * @param buffer
	 * 						字节缓冲流
	 */
	protected ReceivablePacket(int opcode, ByteBuffer buffer)
	{
		this(opcode);
		this.buffer = buffer;
	}

	
	/**
	 * 构建一个数据包，并设置操作码
	 * 如果使用此构造函数，之后必须使用{@link #setBuffer(ByteBuffer)}设置字节缓冲流
	 * @param opcode
	 * 						操作码
	 */
	protected ReceivablePacket(int opcode)
	{
		super(PacketType.CLIENT, opcode);
	}

	
	/**
	 * 获得这个包的所有者
	 * @return			返回这个包的所有者
	 */
	public T getConnection()
	{
		return connection;
	}

	
	/**
	 * 设置这个包的所有者
	 * @param connection		连接
	 */
	public void setConnection(T connection)
	{
		this.connection = connection;
	}

	
	/**
	 * 设置这个包的字节缓冲流
	 * @param buffer			缓冲流
	 */
	public void setBuffer(ByteBuffer buffer) 
	{
		this.buffer = buffer;
	}
	
	/**
	 * 获得字数据包字节缓冲流剩余的字节数
	 * @return			剩余的字节数
	 */
	public int getRemaining()
	{
		return this.buffer.remaining();
	}
	
	
	/**
	 * 从字节缓冲流中读取数据包的数据。
	 * @return		true	读取成功
	 * 				false	读取失败
	 */
	public final boolean read()
	{
		try
		{
			readImpl();
			
			if(this.getRemaining() > 0)
				log.debug("数据包" + this + "没有读取完整。");
			
			return Boolean.TRUE;
		}
		catch (Exception e)
		{
			log.error("读取数据包出错：" + this, e);
			return Boolean.FALSE;
		}
	}
	
	
	/**
	 * 数据读取执行
	 */
	protected abstract void readImpl();
	
	
	
	/**
	 * 数据包的动作，需要用run方法执行此方法。
	 */
	protected abstract void runImpl();
	
	
	/**
	 * 从数据包中读取一个byte。（长度：1）
	 * @return		返回读取的byte的int表示
	 */
	protected final int readByte()
	{
		return this.buffer.get();
	}
	
	/**
	 * 从数据包中读取一个short。（长度：2）
	 * @return		返回读取的short的int表示
	 */
	protected final int readShort()
	{
		return this.buffer.getShort();
	}
	
	/**
	 * 从数据包中读取一个int。（长度：4）
	 * @return		返回读取的int
	 */
	protected final int readInt()
	{
		return this.buffer.getInt();
	}
	
	/**
	 * 从数据包中读取一个float。（长度：4）
	 * @return		返回读取的float
	 */
	protected final float readFloat()
	{
		return this.buffer.getFloat();
	}
	
	/**
	 * 从数据包中读取一个double。（长度：8）
	 * @return		返回读取的double
	 */
	protected final double readDouble()
	{
		return this.buffer.getDouble();
	}
	
	/**
	 * 从数据包中读取一个long。（长度：8）
	 * @return		返回读取的long
	 */
	protected final long readLong()
	{
		return this.buffer.getLong();
	}
	
	
	/**
	 * 从数据包读取一个String。（长度:不限）
	 * @return		返回读取的String
	 */
	protected final String readString()
	{
		StringBuilder sb = new StringBuilder();
		
		char ch;
		
		while((ch = this.buffer.getChar()) != 0)
			sb.append(ch);
		
		return sb.toString();
	}
	
	/**
	 * 从数据包读取一个指定长度的字节数组。
	 * @param length		读取的长度
	 * @return			返回字节数组
	 */
	protected final byte[] readBytes(int length)
	{
		byte[] bytes = new byte[length];
		
		this.buffer.get(bytes);
		
		return bytes;
	}
	
	/**
	 * 从数据包中把剩余的数据以字节数组的形式全部读取
	 * @return			返回字节数组
	 */
	protected final byte[] readBytesOver()
	{
		byte[] bytes = new byte[this.buffer.remaining()];
		
		this.buffer.get(bytes);
		
		return bytes;
	}
	
}
